package console;

import java.io.IOException;
import java.util.HashMap;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.net.URI;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import managers.SeedHandler;

import core.Crawler;
import database.ImageHandler;

public class Console extends Thread
{
	private static Console mInstance;
	private volatile boolean mRunning;
	private BufferedReader mInput;
	
	private HashMap<Commands,Pattern> mPatterns;
	
	public static Console getInstance()
	{
		if (mInstance != null)
			return mInstance;
		else
		{
			mInstance = new Console();
			return mInstance;
		}
	}
	
	/* compiles command regexes and assigns them to command codes */
	private void compilePatterns()
	{
		mPatterns = new HashMap<Commands, Pattern>();
		
		mPatterns.put(Commands.CMD_QUIT, Pattern.compile("^quit$") );
		mPatterns.put(Commands.CMD_SEED, Pattern.compile("^seed\\s+(.*?)$") );
		mPatterns.put(Commands.CMD_STATUS, Pattern.compile("^status$") );
		mPatterns.put(Commands.CMD_HELP, Pattern.compile("^help$") );
		mPatterns.put(Commands.CMD_CURRENT, Pattern.compile("^current$") );
	}
	
	private Console()
	{
		mRunning = true;
		InputStreamReader converter = new InputStreamReader(System.in);
		mInput = new BufferedReader(converter);
		compilePatterns();
	}
	
	/* stops the console thread */
	public void stopProcess()
	{
		mRunning = false;
	}
	
	/* get command details (code + arguments) from inputed command */
	private CommandDetails getCommandDetails( String cmd )
	{
		for (Commands code : Commands.values()) 
		{
			if ( mPatterns.containsKey(code) )
			{
				Matcher m = mPatterns.get(code).matcher(cmd);
				if ( m.find() )
				{
					String [] args = new String[ m.groupCount() + 1 ];
					for ( int i = 0; i <= m.groupCount(); i++ )
					{
						args[i] = m.group(i);
					}
				
					return new CommandDetails(code, args);
				}
			}
		}
		
		return null;
	}
	
	/* handles a line of input */
	public void handleInput(String cmd)
	{
		if ( cmd.isEmpty() )
		{
			return;
		}
		
		CommandDetails details = getCommandDetails( cmd );
		if (details == null )
		{
			System.out.println("Command not found! Type 'help' if you are not sure about commands!");
			return;
		}
		
		/* Command Actions */
		switch ( details.mCode )
		{
			case CMD_QUIT:
				Crawler.getInstance().stopProcess();
			break;
			
			case CMD_CURRENT:
				System.out.println("Current seed is " + Crawler.getInstance().getCurrentWebsite());
			break;
			
			case CMD_HELP:
				System.out.println("Commands:");
				System.out.println("status      - General crawler info.");
				System.out.println("seed URL    - Queue URL for crawling.");
				System.out.println("help        - Show this info.");
				System.out.println("current     - Show current seed.");
				System.out.println("quit        - Close crawler process and save state.");
			break;
			
			case CMD_STATUS:
				// TODO
				System.out.println("Status:");
				
				System.out.println("Crawl Workers busy : " + Crawler.getInstance().getBusyCrawlWorkerCount() + "/" + Crawler.getInstance().getCrawlWorkerCount());
				System.out.println("Queue crawl (pages to be crawled this session): " + Crawler.getInstance().getCrawlQueueSize() + "/" + Crawler.getInstance().getCrawlQueueMaxSize());
				System.out.println("Queue pending (pages to be checked this session): " + Crawler.getInstance().getFoundQueueSize() + "/" + Crawler.getInstance().getFoundQueueMaxSize());
				System.out.println("Queue images (images to be saved): " + Crawler.getInstance().getImageQueueSize());
				System.out.println("Queue potential seeds: " + Crawler.getInstance().getImageQueueSize());
				System.out.println("Queue accepted seeds: " + SeedHandler.getInstance().getValidateQueueSize());
				System.out.println("Images this session: " + ImageHandler.getInstance().getTotalImages());
			break;
			
			case CMD_SEED:
				try 
				{
					URI url= URI.create(details.mArgs[1]).normalize();
					
					try
					{
						if ( url.getScheme() == null )
						{
							url = URI.create("http://" + url.toString());
						}
						Crawler.getInstance().addForcedSeed( url );
						System.out.println("Added URL seed " + url.toString());
					}
					catch (IllegalArgumentException e) 
					{
						System.out.println("Invalid URL! Seed not added!");
					}
					
				}
				catch (IllegalArgumentException e)
				{
					System.out.println("Failed to add url, invalid characters.");
				}
				
			break;
			
			default:
				System.out.println("Command not found! Type 'help' if you are not sure about commands!");
		}
		
	}
		
	public void run()
	{
		Thread.currentThread().setName("CONSOLE");
		System.out.println("For commands type 'help'!");
		
		while ( mRunning )
		{
			try
			{
				System.out.print(">");
				handleInput( mInput.readLine() );
			}
			catch (IOException e) 
			{
				e.printStackTrace();
			}
		}
	}
}
